import logging
import pickle

from flask import jsonify, request
from werkzeug.exceptions import BadRequest

from app import db, facenet
from app.model.models import User, Photo, FaceModel
from app.utils import file_utils, encryption_utils
from . import bp

LOG = logging.getLogger(__name__)


@bp.route('/users', methods=['GET'])
def get_users():
    page = request.args.get('page', 1, type=int)
    per_page = min(request.args.get('per_page', 10, type=int), 100)
    username = request.args.get('username', None)
    if username:
        query = User.query.filter(User.username.like(f'{username}%'))
    else:
        query = User.query
    data = User.to_collection_dict(query, page, per_page, 'api.get_users')
    # Add models
    user_query_list = data['items']
    user_ids = [user['id'] for user in user_query_list]
    photo_model_names = Photo.query.with_entities(Photo.user_id, Photo.model_name) \
        .filter(Photo.user_id.in_(user_ids)).group_by(Photo.user_id, Photo.model_name).all()
    photo_model_name_dict = {}
    for photo_model_name in photo_model_names:
        if photo_model_name.user_id not in photo_model_name_dict:
            photo_model_name_dict[photo_model_name.user_id] = [photo_model_name.model_name]
        else:
            photo_model_name_dict[photo_model_name.user_id].append(photo_model_name.model_name)
    for item in user_query_list:
        item['models'] = photo_model_name_dict[item['id']]
    return jsonify(success=True, data=data, status_code=200)


@bp.route('/user', methods=['POST'])
def add_user():
    data = request.json or {}
    if 'username' not in data \
            or 'cell_phone_number' not in data \
            or 'model_id' not in data \
            or 'photos' not in data:
        raise BadRequest('Must include name, cell_phone_number, model_id and photos.')
    username = data['username']
    cell_phone_number = data['cell_phone_number']
    model_id = int(data['model_id'])
    photos = data['photos']
    # User
    user = User.query.filter_by(username=username, cell_phone_number=cell_phone_number).first()
    if not user:
        u = User()
        u.from_dict(data)
        db.session.add(u)
        user = User.query.filter_by(username=username, cell_phone_number=cell_phone_number).first()
    # FaceModel
    face_model = FaceModel.query.filter_by(id=model_id).first()
    if not face_model:
        raise BadRequest('Unsupported model.')
    # Photo
    photo_count = Photo.query.filter_by(id=user.id).count()
    for i in range(len(photos)):
        input_image = file_utils.resize_blob_to(photos[i])
        embedding = facenet.get_embeddings(input_image)
        data, ext = file_utils.split_data_ext(photos[i])
        photo_name = '{}-{}-{}'.format(user.username, user.cell_phone_number, str(i + 1 + photo_count))
        photo_name = '{}.{}'.format(encryption_utils.encrypt(photo_name), ext)
        file_utils.write_photo(data, photo_name)
        p = Photo(photo_name=photo_name, embedding=pickle.dumps(embedding), user_id=user.id,
                  model_id=model_id, model_name=face_model.model_name)
        db.session.add(p)
    db.session.commit()
    return jsonify(success=True, data=None, status_code=200)


@bp.route('/user', methods=['DELETE'])
def delete_user():
    user_id = request.args.get('id', default=0, type=int)
    if not user_id:
        raise BadRequest('Illegal Request!')
    photos = Photo.query.filter_by(user_id=user_id).all()
    if photos:
        for photo in photos:
            file_utils.remove_photo(photo.photo_name)
            db.session.delete(photo)
    user = User.query.filter_by(id=user_id).first()
    db.session.delete(user)
    db.session.commit()
    return jsonify(success=True, data=None, status_code=200)
